import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.joints.MouseJoint;
import pulpcore.Input;
import pulpcore.Stage;
import pulpcore.CoreSystem;
import pulpcore.animation.Bool;
import pulpcore.animation.Timeline;
import pulpcore.animation.Easing;
import pulpcore.animation.event.TimelineEvent;
import pulpcore.image.Colors;
import pulpcore.image.CoreFont;
import pulpcore.image.CoreImage;
import pulpcore.math.CoreMath;
import pulpcore.scene.Scene2D;
import pulpcore.sprite.Button;
import pulpcore.sprite.*;
import pulpcore.sprite.Label;
import pulpfizz.physics.BodyUtils;
import pulpfizz.physics.Material;
import pulpfizz.physics.NewWorld;
import pulpfizz.pulp.CameraSprite;
import pulpfizz.pulp.body.BodySprite;
import pulpfizz.pulp.body.Java2DBodySprite;
import pulpfizz.pulp.ui.LabelBox;
import pulpfizz.pulp.ui.SmoothMouse;

import java.awt.*;
import java.util.ArrayList;

public class Pulptron extends Scene2D
{
    
    private SmoothMouse sm;
	private MouseJoint mj;
	private Arena physics;
    private Label sprite;
    private BodySprite boxSprite;
    private BodySprite bodySprite;
    private ArrayList<BodySprite> creatures = new ArrayList<BodySprite>();
    private ArrayList<BodySprite> boxes = new ArrayList<BodySprite>();
    private Player player;
    private ComputerPlayer cpu;

    LabelBox hudSprite;
    private final int moveSpeed = 500;
    private static final int NUM_BULLETS = 100;
    private static final int NUM_CREATURES = 2;
    private static final int NUM_TARGETS = 3;
    private Label scoreLabel;
    private FilledSprite fadeSprite;
    private CoreFont font;
    private Label pausedLabel;
    private Button quit;
    private Button muteButton;

    @Override
	public void load()
	{
        super.load();
        Stage.setFrameRate(60);

		Group trueBackground = getMainLayer();
//		camera.setRespondToInput(false);

		CameraSprite asdf = new CameraSprite();
        hudSprite = new LabelBox("",0,0);
        trueBackground.add(asdf);
        trueBackground.add(hudSprite);
        
		/*
		 * Create a Physics sprite, with objects display at 20x their size.
		 */
		physics = new Arena(20);

        physics.setAnchor(Sprite.CENTER);
		add(physics);
		physics.fitToStage();

        physics.setGravity(new Vec2(0,0));
        //		double min = Math.min(physics.width.get(), physics.height.get());
		//		physics.setSize(min, min);
//        ImageSprite bg = new ImageSprite("background.png", 0, 0);
//        physics.add(bg);

		createWorld();

        muteButton = new Button(CoreImage.load("mute.png").split(3,2), Stage.getWidth()-10, Stage.getHeight()-10, true);
        muteButton.setSelected(!CoreSystem.isMute());
        muteButton.setPixelLevelChecks(false);
        muteButton.setAnchor(Sprite.SOUTH_EAST);
        add(muteButton);

        font = CoreFont.load("digital.font.png").scale(1.5);
        final Label ready = new Label(font,"READY",Stage.getWidth()/2,Stage.getHeight()/2);
        final Label go = new Label(font,"GO!",Stage.getWidth()/2,Stage.getHeight()/2);
        ready.setAnchor(Sprite.SOUTH);
        go.setAnchor(Sprite.SOUTH);
        add(ready);

        Timeline t = new Timeline();
        t.animate(ready.alpha,0,255,500);
        t.at(3000).animate(ready.alpha,255,0,500);

        // Wait 3 seconds before firing
        t.addEvent(new TimelineEvent(3500) {
            public void run() {
                player.canFire.set(true);
                cpu.canFire.set(true);
                remove(ready);
                add(go);
                go.alpha.animate(255,0,3000);
            }});

        addTimeline(t);

        quit = Button.createLabeledButton("Exit", Stage.getWidth()/2,Stage.getHeight()-20);
        quit.setAnchor(Sprite.CENTER);
        add(quit);
    }

    Body b;

	public void createWorld()
	{
		NewWorld world = physics.getWorld();

		Material m;

		//		PhysicsUtils.createHollowBox(world, 0, 0, 10, 10, .1f, false);

        // World container.
        Body body = BodyUtils.createHollowBox(world, 0, 0, 40, 30, 2f);
        m = Material.DEAD_WEIGHT();
        m.apply(body);
        physics.add(new Java2DBodySprite(body,physics,1, Color.DARK_GRAY,Color.black,Color.black));

        // Target.
        for(int i=0;i<NUM_TARGETS;i++) {
            physics.spawnTarget(0,(float)CoreMath.rand(-10.0,10.0));
        }
/*
        Body body1 = BodyUtils.createRoundRectangle(world, 2, 2, 2, 2,0.5f,Material.DEAD_WEIGHT());
        boxSprite = new Target(body1, physics,5);
        physics.add(boxSprite);
        Body body2 = BodyUtils.createBox(world, 3, 2, 1, 1,Material.DEAD_WEIGHT());
        BodySprite box = new Target(body2, physics, 5);

        physics.add(box);
        boxes.add(boxSprite);
        boxes.add(box);
*/

        // Create Player
        Player p = new Player(physics,-15,0,0.5f,10);
        physics.add(p);
        player = p;

        m = new PlayerMaterial();
        sm = new SmoothMouse();

		setCursor(Input.CURSOR_HAND);


        // Create CPU Player
        ComputerPlayer cp = new ComputerPlayer(physics,15,0,0.5f,10);
        physics.add(cp);
        cpu = cp;

/*
		MouseJointDef md = new MouseJointDef();
		md.body1 = world.getGroundBody();
		md.body2 = b;
		md.maxForce = 600.0f * b.getMass();
		md.dampingRatio = 0.7f;
		md.frequencyHz = 4;
		mj = (MouseJoint) world.createJoint(md);
		mj.setTarget(new Vec2(0, 0));
*/

        // Add bullets to use
        for (int i = 0; i < NUM_BULLETS; i++) {
            float x;
            if((i & 0x01) == 0) {
                x = (float) CoreMath.rand(-18.0, -17.0);
            } else {
                x = (float) CoreMath.rand(17.0, 18.0);
            }
            float y = (float) CoreMath.rand(-13.0, 13.0);
            double angle = CoreMath.rand(0,Math.PI*2);
            double speed = CoreMath.rand(0.0,1500.0);
            physics.add(new Shot(physics, x, y, 0.2f, 0, 0));
        }

        for (int j = 0; j < NUM_CREATURES; j++)
		{
            Creature c = new Creature(physics,j);
            physics.add(c);
        }


	}

	@Override
	public synchronized void add(Sprite sprite)
	{
		super.add(sprite);
	}

    int timeElapsed = 0, numFrames=0;
    static final int[] keysUp = new int[]{Input.KEY_W,Input.KEY_UP};
    static final int[] keysDown = new int[]{Input.KEY_S,Input.KEY_DOWN};
    static final int[] keysLeft = new int[]{Input.KEY_A,Input.KEY_LEFT};
    static final int[] keysRight = new int[]{Input.KEY_D,Input.KEY_RIGHT};

    Bool canFire = new Bool(false);

    @Override
	public void update(int elapsedTime)
	{
		super.update(elapsedTime);
		sm.update(elapsedTime);

		/* The physics-coordinates of the current mouse location. */
		double pX = physics.getPhysicsX(sm.x.get(), sm.y.get());
		double pY = physics.getPhysicsY(sm.x.get(), sm.y.get());
//		mj.m_target.set((float) pX, (float) pY);

/*
        // Push all boxes towards the player.
        for(BodySprite c : boxes) {
            c.pushTowards(player.getBody().getPosition().x,player.getBody().getPosition().y,10);
        }
*/

        // Use arrow keys/wasd to control player movement
        if(Input.isDown(keysUp)) {
            player.push(0,1, moveSpeed);
        }
        if(Input.isDown(keysDown)) {
            player.push(0,-1, moveSpeed);
        }
        if(Input.isDown(keysLeft)) {
            player.push(-1,0, moveSpeed);
        }
        if(Input.isDown(keysRight)) {
            player.push(1,0, moveSpeed);
        }

        // Fire shots at the mouse cursor when pressed
        if(Input.isMouseDown() && player.canFire()) {
            player.fireShot(pX,pY);
        }

        if(Input.isDown(Input.KEY_MOUSE_BUTTON_3)) {
//            CoreSystem.print("mouse3");
        }
        if(Input.isPressed(Input.KEY_MOUSE_BUTTON_3)) {
//            player.chargeShot();
        }
        if(Input.isReleased(Input.KEY_MOUSE_BUTTON_3)) {
//            player.fireChargedShot(pX,pY,0.2);
        }

        // Orient the computer player's shot towards the nearest obstacle.

        // Orient the player towards the mouse cursor.
        double dy = pY - player.getBody().getWorldCenter().y;
        double dx = pX - player.getBody().getWorldCenter().x;
        int i = -CoreMath.atan2(CoreMath.toFixed(dy), CoreMath.toFixed(dx)) + CoreMath.ONE_HALF_PI;

        // This check is to ensure the shortest rotation direction between angles
        if(CoreMath.abs(player.angle.getAsFixed()-i) > CoreMath.PI) {
            if(i > player.angle.getAsFixed()) player.angle.setAsFixed(player.angle.getAsFixed() + CoreMath.TWO_PI);
            else player.angle.setAsFixed(player.angle.getAsFixed() - CoreMath.TWO_PI);
        }
        player.angle.animateToFixed(i,100);


        // FPS counter
        timeElapsed += elapsedTime;
        numFrames++;
        if(timeElapsed >= 1000) {
            timeElapsed = 0;
            hudSprite.setText("FPS="+ numFrames);
            numFrames=0;
        }

        if(!Input.hasKeyboardFocus()) {
            if(!isPaused()) {
                setPaused(true);
                fadeSprite = new FilledSprite(Colors.rgba(Colors.BLACK,150));
                pausedLabel = new Label(font,"PAUSED", Stage.getWidth()/2,Stage.getHeight()/3);
                pausedLabel.setAnchor(Sprite.CENTER);
                add(fadeSprite);
                add(pausedLabel);
            }
        } else {
            if(isPaused()) {
                remove(fadeSprite);
                remove(pausedLabel);
                setPaused(false);
            }
        }

        if(quit.isClicked()) {
            quit.scaleTo(0,0,500, Easing.STRONG_IN_OUT);
            fadeSprite = new FilledSprite(Colors.rgba(Colors.BLACK,255));
            add(fadeSprite);
            fadeSprite.alpha.animate(0,255,500);
            Timeline t = new Timeline();
            t.addEvent(new TimelineEvent(500) { public void run() {
                    Stage.setScene(new MainMenuScene());
                }});
            addTimeline(t);
        }
        if (muteButton.isClicked()) {
            CoreSystem.setMute(!muteButton.isSelected());
        }
    }
}
